/*
 * @Author: liuzelin
 * @Date: 2024-04-06 12:28:15
 * @LastEditors: liuzelin
 * @LastEditTime: 2024-05-19 21:17:10
 * @Description: file content
 */
#pragma once

#include <future>

#include "panda_socket.hpp"
#include "panda_timer.hpp"
#include "panda_resolver.hpp"
namespace Panda {
typedef std::function<void()> PandaTask;

class PANDA_EXPORT TaskLocation {
 public:
  explicit TaskLocation( const char* file, const char* func, int line );
  TaskLocation() = default;
  TaskLocation( TaskLocation& other );
  TaskLocation& operator=( TaskLocation& other );
  bool operator == ( const TaskLocation& other ) const;
  const char* File() const { return file_; }
  const char *Function() const { return func_; }
  int Line() const { return line_; }

 private:
  const char *file_;
  const char *func_;
  int line_;
};

#define PandaFromHere Panda::TaskLocation(__FILE__, __FUNCTION__, __LINE__)

class PANDA_EXPORT Thread {
 public:
  virtual ~Thread() = default;
  virtual void Start() = 0;
  virtual void Stop() = 0;
  virtual void SetThreadName(const char *name) = 0;
  virtual const char *Name() const = 0;
  virtual bool IsCurrent() const = 0;

  virtual UDPSocket *CreateUDPSocket() = 0;
  virtual TCPSocket *CreateTCPSocket() = 0;
  virtual Timer *CreateTimer() = 0;
  virtual Resolver *CreateResolver() = 0;

  void Invoke(TaskLocation location, PandaTask func) {
    if (IsCurrent()) {
      return func();
    } else {
      std::promise<bool> ret;
      PostTask(location, [&]() {
        func();
        ret.set_value(true);
      });
      ret.get_future().get();
      return;
    }
  }
  template <typename Ret>
  Ret Invoke(TaskLocation location, std::function<Ret()> func) {
    if (IsCurrent()) {
      return func();
    } else {
      std::promise<Ret> ret;
      PostTask(location, [&]() { ret.set_value(func()); });
      return ret.get_future().get();
    }
  }

  virtual void PostTask(TaskLocation location, PandaTask func) = 0;
  virtual void ClearDelayTask(void *key) = 0;
  virtual void PostDelayTask(TaskLocation location, PandaTask func,
                             uint64_t delay, void *key = nullptr) = 0;
};

class PANDA_EXPORT ThreadManager {
 public:
  static ThreadManager *Instance();
  virtual Thread *CreateThread() = 0;
  virtual Thread *Current() = 0;
  virtual void EnableCalculateTaskCost(bool enable) = 0;
  virtual void ExportTaskCostStat(const char *dir) = 0;
  virtual ~ThreadManager() = default;
};

class PANDA_EXPORT ThreadPoolManager {
 public:
  static ThreadPoolManager *Instance();
  virtual void Start(int thread_num = 0) = 0;
  void Invoke(TaskLocation location, PandaTask func) {
    std::promise<bool> ret;
    PostTask(location, [&]() {
      func();
      ret.set_value(true);
    });
    ret.get_future().get();
    return;
  }
  template <typename Ret>
  Ret Invoke(TaskLocation location, std::function<Ret()> func) {
    std::promise<Ret> ret;
    PostTask(location, [&]() { ret.set_value(func()); });
    return ret.get_future().get();
  }
  virtual void PostTask(TaskLocation location, PandaTask func) = 0;
  virtual ~ThreadPoolManager() = default;
};
}  // namespace Panda
